/*
 * This file is part of Cadmium.
 * Copyright (C) 2007-2010 Xavier Clerc.
 *
 * Cadmium is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Cadmium is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package fr.x9c.cadmium.kernel;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * This class implements a thread running ocaml code. <br/>
 * It also provides methods returning unique thread (group) names. <br/>
 * <br/>
 * All Cadmium thread (for interpreted as well as for native) code belong to
 * the same thread group hierarchy.
 *
 * @author <a href="mailto:cadmium@x9c.fr">Xavier Clerc</a>
 * @version 1.0
 * @since 1.0
 */
public final class CadmiumThread extends Thread {

    /** Prefix for parent thread group of an interpreted runner. */
    private static final String INTERP_THREAD_GROUP_PREFIX =
        "Cadmium-Interpreter-";

    /** Prefix for parent thread group of a native runner. */
    private static final String NATIVE_THREAD_GROUP_PREFIX =
        "Cadmium-Native-";

    /** Next identifier for parent thread group of a program. */
    private static final AtomicInteger NEXT_GROUP_ID = new AtomicInteger();

    /** Prefix for thread names. */
    private static final String THREAD_PREFIX = "Cadmium-Thread-";

    /** Next integer identifier for name. */
    private static final AtomicInteger NEXT_THREAD_ID = new AtomicInteger();

    /** Code that thread actually runs. */
    private final CodeRunner runner;

    /** Whether the thread is paused. */
    private boolean paused;

    /**
     * Constructs a thread from group and code to run.
     * @param group thread group - should not be <tt>null</tt>
     * @param runner code to run - should not be <tt>null</tt>
     */
    public CadmiumThread(final ThreadGroup group,
                         final CodeRunner runner) {
        super(group, runner, getNextName());
        assert group != null : "null group";
        assert runner != null : "null runner";
        this.runner = runner;
        this.paused = false;
    } // end constructor(ThreadGroup, CodeRunner)

    /**
     * Returns the code that the thread actually runs.
     * @return the code that the thread actually runs
     */
    public CodeRunner getRunner() {
        return this.runner;
    } // end method 'getRunner()'

    /**
     * Asks the thread to pause its execution. <br/>
     * <b>Thread unsafe.</b>
     */
    @SuppressWarnings("deprecation")
    public void pause() {
        this.paused = true;
        super.suspend();
    } // end method 'pause()'

    /**
     * Asks the thread to resume its execution. <br/>
     * <b>Thread unsafe.</b>
     */
    @SuppressWarnings("deprecation")
    public void wakeUp() {
        this.paused = false;
        super.resume();
    } // end method 'wakeUp()'

    /**
     * Tests whether the thread is paused.
     * @return <tt>true</tt> if the thread is paused,
     *         <tt>false</tt> otherwise
     */
    public boolean isPaused() {
        return this.paused;
    } // end method 'isPaused()'

    /**
     * Asks the thread to stop its execution. <br/>
     * <b>Thread unsafe.</b>
     */
    @SuppressWarnings("deprecation")
    public void asksToStop() {
        try {
            super.stop();
        } catch (final ThreadDeath td) {
            // nothing to do
        } // end try/catch
    } // end method 'asksToStop()'

    /**
     * Returns the next thread group name. <br/>
     * Thread group names are of the following form:
     * <tt>Cadmium-<i>type</i>-<i>id</i></tt> where <i>type</i> is
     * either <tt>Interpreter</tt> or <tt>Native</tt> according to passed
     * boolean, and <i>id</i> is a unique integer identifier that is
     * incremented each time a new thread group is created.
     * @param isNative whether the underlying code runner is native
     * @return the next thread group name
     */
    static String getNextThreadGroupName(final boolean isNative) {
        final StringBuilder sb =
            new StringBuilder(isNative
                              ? CadmiumThread.NATIVE_THREAD_GROUP_PREFIX
                              : CadmiumThread.INTERP_THREAD_GROUP_PREFIX);
        sb.append(CadmiumThread.NEXT_GROUP_ID.getAndIncrement());
        return sb.toString();
    } // end method 'getNextThreadGroupName(boolean)'

    /**
     * Returns the next thread name. <br/>
     * Threads names are of the following form:
     * <tt>Cadmium-Thread-<i>id</i></tt> where <i>id</i> is a unique
     * integer identifier that is incremented each time a new thread is
     * created.
     * @return the next thread name
     */
    private static String getNextName() {
        final StringBuilder sb =
            new StringBuilder(CadmiumThread.THREAD_PREFIX);
        sb.append(CadmiumThread.NEXT_THREAD_ID.getAndIncrement());
        return sb.toString();
    } // end method 'getNextName()'

} // end class 'CadmiumThread'
